﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;

namespace Calculate
{
    [ComVisible(true), ClassInterface(ClassInterfaceType.None)]
    public class Calculate : ICalculate
    {
        static MemoryMappedFile memoryMappedFileMediator;
        static MemoryMappedViewAccessor memoryMappedFileView;
        static string tempMessage;
        static Random r;
        static Calculate()
        {
            r = new Random(1);
            memoryMappedFileMediator = MemoryMappedFile.CreateOrOpen("testfile", 1000, MemoryMappedFileAccess.ReadWrite);
            memoryMappedFileView = memoryMappedFileMediator.CreateViewAccessor();

        }

        public Calculate()
        {
            DoubleArray = new double[] { };
            ClassArray = new Point[] { };
        }

        private Point _point;
        public Point Point
        {
            get { return _point; }
            set { _point = value; }
        }

        double _Number;
        public double Number
        {
            get { return _Number; }
            set
            {
                if (_Number != value)
                    _Number = value;
            }
        }

        private double[] _doubleArray;
        public double[] DoubleArray
        {
            get { return _doubleArray; }
            set { _doubleArray = value; }
        }

        private Point[] _classArray;
        public Point[] ClassArray
        {
            get { return _classArray; }
            set { _classArray = value; }
        }


        public void GenerateRandom()
        {
            Number = r.Next(1, 10000);
            List<double> dl = new List<double>();
            List<Point> pl = new List<Point>();
            for (int i = 0; i < 10; i++)
            {
                dl.Add(r.Next(1, 5000));
                pl.Add(new Point() { X = r.Next(1, 100), Y = r.Next(1, 100) });
            }
            DoubleArray = dl.ToArray();
            ClassArray = pl.ToArray();
            WriteToMemory();
        }

        public double Mult(double a, double b)
        {

            return a * b;
        }

        public void Add(double a)
        {
            ReadFromMemory();//Читаем то что есть в памяти
            Number += a;
            WriteToMemory();//Записываем новое значение в память
        }

        //закрытый метод записи в файл в памяти
        private void WriteToMemory()
        {
            //Формируется строка для записи в файл в памяти
            StringBuilder sb = new StringBuilder();
            StringBuilder sbDoubleArray = new StringBuilder();
            StringBuilder sbPointArray = new StringBuilder();
            sb.AppendLine(Number.ToString());
            foreach (var d in DoubleArray)
            {
                sbDoubleArray.Append(string.Format(@"{0};", d));
            }
            sb.AppendLine(sbDoubleArray.ToString().TrimEnd(';'));
            foreach (var p in ClassArray)
            {
                sbPointArray.Append(string.Format(@"{0}.{1};", p.X, p.Y));
            }
            sb.AppendLine(sbPointArray.ToString().TrimEnd(';'));

            tempMessage = sb.ToString();

            //Запись в файл в памяти
            System.Byte[] smsg = Encoding.Default.GetBytes(sb.ToString());
            var b = (byte)smsg.Length;
            //memoryMappedFileView.Write<System.Byte>(0, ref b);
            System.Byte[] message;
            memoryMappedFileView.Write<double>(0, ref _Number);
            message = new System.Byte[memoryMappedFileView.ReadByte(0)];
            memoryMappedFileView.WriteArray<double>(0, _doubleArray, 0, _doubleArray.Length);
            memoryMappedFileView.WriteArray<Point>(0, _classArray, 0, _classArray.Length);
            //memoryMappedFileView.WriteArray<System.Byte>(4, smsg, 0, smsg.Length);

        }

        //закрытый метод чтения содержимого файла из памяти
        private void ReadFromMemory()
        {
            using (MemoryMappedFile memoryMappedFileMediator = MemoryMappedFile.OpenExisting("testfile"))
            {
                using (MemoryMappedViewAccessor memoryMappedFileView = memoryMappedFileMediator.CreateViewAccessor())
                {
                    //System.Byte[] message = new System.Byte[memoryMappedFileView.ReadByte(0)];
                    _Number = memoryMappedFileView.ReadDouble(0);
                    memoryMappedFileView.ReadArray<double>(0, _doubleArray, 0, 10);
                    memoryMappedFileView.ReadArray<Point>(0, _classArray, 0, 10);
                    //memoryMappedFileView.ReadArray<System.Byte>(4, message, 0, message.Length);
                    //string curMessage = Encoding.Default.GetString(message, 0, message.Length);

                    //if (curMessage != tempMessage)
                    //{
                    //    tempMessage = curMessage;
                    //    if (string.IsNullOrEmpty(curMessage))
                    //        return;
                    //    ParseMemoryMessage();
                    //}

                }
            }
        }

        //закрытый метод парсинга файла в памяти
        private void ParseMemoryMessage()
        {
            List<string> msgParts = tempMessage.Split('\n').ToList();
            for (int i = 0; i <= msgParts.Count; i++)
            {
                switch (i)
                {
                    case 0:
                        Number = double.Parse(msgParts[0]);
                        break;
                    case 1:
                        string[] dp = msgParts[1].Split(';');
                        if (dp.Count() > 0)
                            DoubleArray = dp.Select(d => double.Parse(d)).ToArray();
                        break;
                    case 2:

                        string[] pp = msgParts[2].Split(';');
                        if (pp.Count() > 0)
                        {
                            List<Point> points = new List<Point>();
                            foreach (var p in pp)
                            {
                                points.Add(new Point()
                                    {
                                        X = double.Parse(p.Split('.')[0]),
                                        Y = double.Parse(p.Split('.')[1])
                                    });
                            }
                            ClassArray = points.ToArray();
                        }
                        break;
                }
            }



        }
    }
    [ComVisible(true)]
    public struct Point
    {
        public double X { get; set; }
        public double Y { get; set; }
    }
}
